﻿using Ocelot.Configuration.File;
using Ocelot.Configuration.Setter;
using YunQue.Gateway;

public class DynamicRouteUpdater : IHostedService
{
    private readonly IFileConfigurationSetter _fileConfigurationSetter;

    public DynamicRouteUpdater(IFileConfigurationSetter fileConfigurationSetter)
    {
        _fileConfigurationSetter = fileConfigurationSetter;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        // 启动定时任务
        Task.Run(async () =>
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                // 从数据库加载最新路由配置
                var newConfig = LoadRoutesFromDatabase();

                // 更新 Ocelot 配置
                await _fileConfigurationSetter.Set(newConfig);

                // 等待一段时间后刷新（例如每隔 30 秒刷新一次）
                await Task.Delay(TimeSpan.FromSeconds(30), cancellationToken);
            }
        }, cancellationToken);

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }

    private FileConfiguration LoadRoutesFromDatabase()
    {
        var routes = new List<FileRoute>();
        //这里需要从数据库或者redis中获取路由模板配置，服务区分普通服务和粘性服务，每种服务都会有一个或者多个实例
        //1.如果是普通服务，相同的服务会有多个实例，使用轮询负载均衡
        //2.如果是粘性服务，使用哈希算法将客户端标识映射到后端服务名
        //3.下游服务采用三级灰度发布的过程，所有会有w  ww   www 的区分
        // 以tenantapi 为例，构建普通服务和粘性服务的路由配置
        List<ServiceModel> serviceList = new List<ServiceModel>()
        {
            //一个普通服务实例
            new ServiceModel()
            {
                ServiceName="tenantapi",
                Host="localhost",
                Port=7066,
                IsHttps=false,
                IsStickiness=false,
                IsHealthCheck=true,
                HealthCheckPath="/api/tenantapi/healthcheck"
            },
            //两个粘性服务实例
            new ServiceModel()
            {
                ServiceName="tenantapi_s",
                Host="localhost",
                Port=7066,
                IsHttps=false,
                IsStickiness=true,
                IsHealthCheck=true,
                HealthCheckPath="/api/tenantapi/healthcheck"
            },
            new ServiceModel()
            {
                ServiceName="tenantapi_s",
                Host="192.168.6.34",
                Port=9101,
                IsHttps=false,
                IsStickiness=true,
                IsHealthCheck=true,
                HealthCheckPath="/api/tenantapi/healthcheck"
            },
        };
        List<string> serviceLevel = new List<string>() { "w", "ww", "www" };
        Dictionary<string, string> downHeaderTransform = new Dictionary<string, string>()
        {
            {"X-Forwarded-For","{RemoteIpAddress}" },
            {"X-Real-IP","{RemoteIpAddress}" }
        };
        //配置服务
        foreach (var level in serviceLevel)
        {
            foreach (var serviceGroup in serviceList.GroupBy(p => p.ServiceName))
            {
                var services = serviceGroup.ToList();
                bool isStickiness = services.FirstOrDefault().IsStickiness;
                //如果是粘性服务，每个服务都要单独配置
                //如果是普通服务，使用轮询负载均衡
                if (isStickiness)
                {
                    int index = 0;
                    foreach (var service in services)
                    {
                        routes.Add(new FileRoute
                        {
                            UpstreamPathTemplate = $"/{level}/api/{service.ServiceName}{index}/{{everything}}",
                            DownstreamPathTemplate = "/api/{everything}",
                            DownstreamHostAndPorts = new List<FileHostAndPort>
                            {
                                new FileHostAndPort
                                {
                                    Host = service.Host,
                                    Port = service.Port
                                }
                            },
                            UpstreamHttpMethod = new List<string> { "GET", "POST", "DELETE", "PUT" },
                            DownstreamHeaderTransform= downHeaderTransform,
                            FileCacheOptions=new FileCacheOptions()
                            {
                                TtlSeconds=30,
                                Region= "Default"
                            }
                        });
                        index++;
                    }
                }
                else
                {
                    routes.Add(new FileRoute
                    {
                        UpstreamPathTemplate = $"/{level}/api/{serviceGroup.Key}/{{everything}}",
                        DownstreamPathTemplate = "/api/{everything}",
                        DownstreamHostAndPorts = services.Select(s => new FileHostAndPort
                        {
                            Host = s.Host,
                            Port = s.Port
                        }).ToList(),
                        UpstreamHttpMethod = new List<string> { "GET", "POST", "DELETE", "PUT" },
                        DownstreamHeaderTransform = downHeaderTransform,
                        LoadBalancerOptions = new FileLoadBalancerOptions
                        {
                            Type = "RoundRobin" // 设置轮询负载均衡
                        }
                    });
                }
            }
        }
        return new FileConfiguration
        {
            Routes = routes,
        };
    }
}